package service

import (
	"im/dao"
	"im/model"
	"im/requests"
	"im/responses"
)

type Replys interface {
	GetFirstLevelReplysByPostId(userId, postId int64, pagination requests.Pagination) ([]responses.ReplyWithBasicInfo, error)
	GetSubReplyList(userId, replyId int64, pagination requests.Pagination) ([]responses.ReplyWithBasicInfo, error)
	GetSubReplyListBatch(userId int64, replyIds ...int64) (map[int64]responses.ReplyWithBasicInfo, error)
	GetSubReplyCountBatch(replyIds ...int64) (map[int64]int, error)
	// 这里区分了直接回复的id和top回复的id,topid主要用于取数据的时候方便
	Create(userId int64, postId, replyId int64, postReplys requests.PostReplys) error
	// 点赞
	Like(userId, postId, replyId int64) error
	Unlike(userId, postId, replyId int64) error
	Get(userId int64, replyId int64) (responses.ReplyWithBasicInfo, error)
}

func NewReplys() Replys {
	return replys{d: dao.NewReplys()}
}

type replys struct {
	d dao.Replys
}

func (r replys) Get(userId int64, replyId int64) (responses.ReplyWithBasicInfo, error) {
	var resp responses.ReplyWithBasicInfo
	m, err := r.d.GetById(replyId)
	if err != nil {
		return resp, err
	}
	likedMap, err := r.d.GetLikedReplysIdsBatch(userId, replyId)
	if err != nil {
		return resp, err
	}
	var liked = 0
	if _, ok := likedMap[replyId]; ok {
		liked = 1
	}
	postUser, err := NewUserService().GetInfoById(m.UserId)
	if err != nil {
		return resp, err
	}
	resp.Replys = m
	resp.Liked = liked
	resp.Nickname = postUser.Nickname
	resp.Avatar = postUser.Avatar
	return resp, nil
}

func (r replys) GetSubReplyCountBatch(replyIds ...int64) (map[int64]int, error) {
	var resp = map[int64]int{}
	cs, err := r.d.GetSubReplCountBatch(replyIds...)
	if err != nil {
		return resp, err
	}
	for _, row := range cs {
		resp[row.ToTopReplyId] = row.Cnt
	}
	return resp, nil
}

func (r replys) GetSubReplyListBatch(userId int64, replyIds ...int64) (map[int64]responses.ReplyWithBasicInfo, error) {
	var resp = map[int64]responses.ReplyWithBasicInfo{}
	ms, err := r.d.GetSubReplyListBatch(replyIds...)
	if err != nil {
		return resp, err
	}
	replyWithNicknames := r.appendUserIdForReplys(userId, ms)
	for _, row := range replyWithNicknames {
		resp[row.ToTopReplyId] = row
	}
	return resp, nil
}

func (r replys) Unlike(userId, postId, replyId int64) error {
	success, err := dao.NewLikes().UnLike(userId, model.LikesSelector{
		PRId: replyId,
		Type: model.LikesType_Reply,
	})
	if err != nil {
		return err
	}
	// 如果不存在, 直接静默失败
	if !success {
		return nil
	}
	// todo 父级评论的like也要-1
	r.d.SubStat(replyId, model.ReplyStatLikes)
	dao.NewPostsWithEs().SubStat(postId, model.PostStatLikes)
	return nil
}

func (r replys) Like(userId, postId, replyId int64) error {
	exist, err := dao.NewLikes().Like(userId, model.LikesSelector{
		PRId: replyId,
		Type: model.LikesType_Reply,
	})
	if err != nil {
		return err
	}
	// 如果存在, 直接静默失败
	if exist {
		return nil
	}
	r.d.AddStat(replyId, model.ReplyStatLikes)
	dao.NewPostsWithEs().AddStat(postId, model.PostStatLikes)
	return nil
}

func (r replys) Create(userId int64, postId, replyId int64, postReplys requests.PostReplys) error {
	var creatable model.ReplyCreatable
	// 回复评论
	if replyId > 0 {
		parent, err := dao.NewReplys().GetById(replyId)
		if err != nil {
			return err
		}
		topReplyId := parent.ToTopReplyId
		if parent.ToTopReplyId == -1 {
			topReplyId = parent.Id
		}
		creatable = model.ReplyCreatable{
			ToTopReplyId:    topReplyId,
			ToDirectReplyId: parent.Id,
			ToUserId:        parent.UserId,
			ToPostId:        postId,
		}
	} else {
		// 回复帖子
		creatable = model.ReplyCreatable{
			ToTopReplyId:    -1,
			ToDirectReplyId: -1,
			ToUserId:        0,
			ToPostId:        postId,
		}
	}
	var m = model.Replys{
		UId: model.UId{
			UserId: userId,
		},
		ReplyModifiable: postReplys.ReplyModifiable,
		ReplyCreatable:  creatable,
		SeeStatus:       model.Reply_See_EveryBody,
	}
	_, err := dao.NewReplys().Insert(m)
	if err != nil {
		return err
	}
	return dao.NewPostsWithEs().AddStat(postId, model.PostStatComments)
}

func (r replys) GetSubReplyList(userId, replyId int64, pagination requests.Pagination) ([]responses.ReplyWithBasicInfo, error) {
	var resp = []responses.ReplyWithBasicInfo{}
	ms, err := r.d.SubListByReplyId(replyId, pagination)
	if err != nil {
		return resp, err
	}
	resp = r.appendUserIdForReplys(userId, ms)
	return resp, nil
}

func (r replys) GetFirstLevelReplysByPostId(userId, postId int64, pagination requests.Pagination) ([]responses.ReplyWithBasicInfo, error) {
	var resp = []responses.ReplyWithBasicInfo{}
	ms, err := r.d.ListByPostId(postId, pagination)
	if err != nil {
		return resp, err
	}
	resp = r.appendUserIdForReplys(userId, ms)
	return resp, nil
}
func (r replys) appendUserIdForReplys(userId int64, ms []model.Replys) []responses.ReplyWithBasicInfo {
	var userIds = []int64{}
	var replyIds = []int64{}
	var replys = []responses.ReplyWithBasicInfo{}
	for _, v := range ms {
		userIds = append(userIds, v.UserId)
		replyIds = append(replyIds, v.Id)
	}
	userMaps, _ := NewUserService().GetInfoMapByIds(userIds...)
	likedMap, _ := r.d.GetLikedReplysIdsBatch(userId, replyIds...)

	for _, v := range ms {
		liked := 0
		if _, ok := likedMap[v.Id]; ok {
			liked = 1
		}
		replys = append(replys, responses.ReplyWithBasicInfo{
			Replys:   v,
			Nickname: userMaps[v.UserId].Nickname,
			Avatar:   userMaps[v.UserId].Avatar,
			Liked:    liked,
		})
	}
	return replys
}
